﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
using SilverlightUtils;
using TheGameClient.Webservices;

namespace TheGameClient.WorldMap
{
	public partial class WorldMapControl
	{
		private readonly List<ulong> _connectedNodes;
		private NetworkNode _lastConnectionPoint;
		private Point _nodeClickPoint;
		public List<SmallComputerSystem> NodeStorage;

		private bool _simulateButton;

		public WorldMapControl()
		{
			InitializeComponent();
			// Required to initialize variables

			if (_connectedNodes == null)
				_connectedNodes = new List<ulong>();

			LayoutRoot.SizeChanged += delegate
			{
				//mapGrid.Height = _e.NewSize.Width /2;
				LayoutRoot.SetClip();
				PopulateNodes();
				//if (nodeStorage != null)
				//    PopulateNodes(nodeStorage);
			};
		}

		public bool SimulateButton
		{
			get { return _simulateButton; }
			set
			{
				_simulateButton = value;
				if (_simulateButton)
					btnExpandAll.Visibility = Visibility.Collapsed;
			}
		}

		public bool IsAdminMode { get; set; }

		public bool AlwaysShowExpanded { get; set; }

		public List<ulong> ConnectedNodes
		{
			get { return _connectedNodes; }
		}

		public NetworkNode LastConnectionPoint
		{
			get { return _lastConnectionPoint; }
			set { _lastConnectionPoint = value; }
		}

		public event EventHandler<MouseButtonEventArgs> OnClick;

		public void PopulateNodes()
		{
			nodeCanvas.Children.Clear();
			//nodeStorage = nodes;
			double width = ActualWidth;
			double height = ActualHeight;

			LayoutRoot.SetClip();
			if (SimulateButton)
			{
				btnExpandAll.Visibility = Visibility.Collapsed;
				nodeCanvas.Visibility = Visibility.Collapsed;
				zoomer.ZoomEnabled = false;
				zoomer.PanEnabled = false;
				return;
			}

			//var myGatewaySystem = (from item in nodes where item.IsSelected == true).FirstOrDefault();
			foreach (SmallComputerSystem cs in App.MyKnownComputers)
			{
				NetworkNode nwn = new NetworkNode();
				if (cs == null) continue;
				nwn.ComputerSystemId = cs.Id;
				nwn.Hostname = cs.Name;
				if (cs.Corporation == null)
					continue;

				nwn.Corporation = cs.Corporation.Name + " " + cs.Corporation.TopLevelDomain.Name;
				//if node belongs to user's corporation AND is gateway central -> mark red as home system
				if (cs.Corporation.Id == App.MyCorporationId)
					//(n.Gateway != null && n.Gateway.Agent.agentId == App.InternalSessionId)
				{
					if (cs.IsGatewayCentral)
					{
						nwn.MarkerFill = new SolidColorBrush(Colors.Red);
						nwn.IsHomeSystem = true;
					}
					else
					{
						nwn.MarkerFill = new SolidColorBrush(Color.FromArgb(0xff, 0x00, 0xcc, 0xff));
					}
				}
				else
					nwn.MarkerFill = new SolidColorBrush(Colors.White);

				nwn.OnMouseDown += nwn_OnMouseDown;
				nwn.OnMouseUp += nwn_OnMouseUp;
				if (IsAdminMode)
				{
					nwn.OnMouseMoving += nwn_OnMouseMoving;
				}
				nodeCanvas.Children.Add(nwn);
				Canvas.SetLeft(nwn, PercentToCoord(cs.MapX, width));
				Canvas.SetTop(nwn, PercentToCoord(cs.MapY, height));
				if (nwn.RenderTransform is ScaleTransform && zoomer.Zoom > 0)
				{
					(nwn.RenderTransform as ScaleTransform).ScaleX = 1.0/zoomer.Zoom;
					(nwn.RenderTransform as ScaleTransform).ScaleY = 1.0/zoomer.Zoom;
				}
			}
		}

		private void nwn_OnMouseDown(object sender, MouseButtonEventArgs e)
		{
			if (sender is NetworkNode)
			{
				NetworkNode nwn = sender as NetworkNode;
				if (IsAdminMode)
				{
					nwn.IsDragging = true;
					nwn.CaptureMouse();
					_nodeClickPoint = e.GetPosition(nwn);
				}
				else if (SimulateButton)
					return;
				else
				{
					if (_connectedNodes.Count == 0) // list still uninitialized, add home
					{
						NetworkNode home =
							(from n in nodeCanvas.Children.OfType<NetworkNode>() where n.IsHomeSystem select n).FirstOrDefault();
						if (home == null)
							throw new Exception("Error: no home system found. Please notify support.");
						_connectedNodes.Add(home.ComputerSystemId);
					}
					NetworkNode end = sender as NetworkNode;
					if (end.IsHomeSystem)
					{
						if (MessageBox.Show("This will clear the current connection. Continue?", "Warning", MessageBoxButton.OKCancel) ==
						    MessageBoxResult.OK)
						{
							_connectedNodes.Clear();
							connectionCanvas.Children.Clear();
							_lastConnectionPoint = end;
							e.Handled = true;
							return;
						}
					}
					if (_connectedNodes.Contains(end.ComputerSystemId))
						//remove connections from this node, and instead, draw a line from end's previous node to end's next node
					{
						_connectedNodes.Remove(end.ComputerSystemId);
						RedrawConnections();
					}
					else
					{
						NetworkNode begin = LastConnectionPoint;
						if (begin == null)
							begin = (from n in nodeCanvas.Children.OfType<NetworkNode>() where n.IsHomeSystem select n).FirstOrDefault();

						if (begin == null)
							throw new Exception("Error: no home system found.");

						CreateConnection(begin, end);
					}
				}
				e.Handled = true;
			}
		}

		/// <summary>
		///   redraws the current connections using the connectedNodes list
		/// </summary>
		private void RedrawConnections()
		{
			connectionCanvas.Children.Clear();
			ulong[] copy = new ulong[_connectedNodes.Count];
			_connectedNodes.CopyTo(copy);
			_connectedNodes.Clear();
			NetworkNode home =
				(from n in nodeCanvas.Children.OfType<NetworkNode>() where n.IsHomeSystem select n).FirstOrDefault();
			LastConnectionPoint = home;
			if (copy.Length == 1)
			{
				NetworkNode firstpoint =
					(from n in nodeCanvas.Children.OfType<NetworkNode>() where n.ComputerSystemId == copy[0] select n).FirstOrDefault();
				CreateConnection(home, firstpoint);
			}
			for (int i = 0; i < copy.Length - 1; i++)
			{
				if (i == 0) // also create home to first-point connection
				{
					NetworkNode firstpoint =
						(from n in nodeCanvas.Children.OfType<NetworkNode>() where n.ComputerSystemId == copy[i] select n).FirstOrDefault();
					CreateConnection(home, firstpoint);
				}
				NetworkNode begin =
					(from n in nodeCanvas.Children.OfType<NetworkNode>() where n.ComputerSystemId == copy[i] select n).FirstOrDefault();
				NetworkNode end =
					(from n in nodeCanvas.Children.OfType<NetworkNode>() where n.ComputerSystemId == copy[i + 1] select n).
						FirstOrDefault();
				CreateConnection(begin, end);
			}
		}

		private void nwn_OnMouseMoving(object sender, MouseEventArgs e)
		{
			if (sender is NetworkNode)
			{
				NetworkNode nwn = sender as NetworkNode;
				if (!nwn.IsDragging) return;
				Point pos;
				try
				{
					pos = e.GetPosition(nwn);
				}
				catch
				{
					return;
				}
				Point delta = _nodeClickPoint.Subtract(pos);
				delta.X /= zoomer.Zoom;
				delta.Y /= zoomer.Zoom;
				pos = new Point(Canvas.GetLeft(nwn), Canvas.GetTop(nwn));
				Canvas.SetLeft(nwn, pos.X - delta.X);
				Canvas.SetTop(nwn, pos.Y - delta.Y);
			}
		}

		private void nwn_OnMouseUp(object sender, MouseButtonEventArgs e)
		{
			if (!IsAdminMode) return;
			//double width = ActualWidth;
			//double height = ActualHeight;
			//if (sender is NetworkNode)
			//{
			//    NetworkNode nwn = sender as NetworkNode;
			//    nwn.isDragging = false;
			//    U2SvcClient client = App.Client;
			//    client.PersistEntityCompleted += (_s, _e) =>
			//    {
			//        client.ObtainEntitiesByTypeCompleted += client_GetComputerSystemsCompleted;
			//        client.ObtainEntitiesByTypeAsync(App.InternalSessionId, Entities.ComputerSystem);
			//    };
			//    SmallComputerSystem sys = (from s in nodeStorage where s.ID == nwn.ComputerSystemId select s).First();
			//    try
			//    {
			//        MatrixTransform mtx = (MatrixTransform)nwn.TransformToVisual(nodeCanvas);
			//        sys.MapX = CoordToPercent(Canvas.GetLeft(nwn), width);
			//        sys.MapY = CoordToPercent(Canvas.GetTop(nwn), height);
			//        client.PersistEntityAsync(App.InternalSessionId, sys, 0, false);
			//    }
			//    catch (Exception) //ignore exceptions (for now), rare occurance of "Value not in range" for...whatever.
			//    {
			//    }
			//    e.Handled = true;
			//}
		}

		//void client_GetComputerSystemsCompleted(object sender, ObtainEntitiesByTypeCompletedEventArgs e)
		//{
		//    //PopulateNodes(e.Result.Cast<SmallComputerSystem>().ToList());
		//}

		protected override void OnMouseWheel(MouseWheelEventArgs e)
		{
			//if (LayoutRoot.Clip == null)
			//    LayoutRoot.SetClip();

			IEnumerable<NetworkNode> nodes = nodeCanvas.Children.OfType<NetworkNode>();
			foreach (NetworkNode node in nodes)
			{
				if (node.RenderTransform is ScaleTransform && zoomer.Zoom > 0)
				{
					(node.RenderTransform as ScaleTransform).ScaleX = 1.0/zoomer.Zoom;
					(node.RenderTransform as ScaleTransform).ScaleY = 1.0/zoomer.Zoom;
				}
			}

			IEnumerable<Line> lines = connectionCanvas.Children.OfType<Line>();
			foreach (Line l in lines)
			{
				if (zoomer.Zoom > 0)
				{
					l.StrokeThickness = 1.0/zoomer.Zoom;
				}
			}
			e.Handled = true;
		}

		protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
		{
			if (SimulateButton)
			{
				if (OnClick != null)
					OnClick(this, e);
				return;
			}
			e.Handled = true;
		}

		private double PercentToCoord(double percent, double maxValue)
		{
			if (percent > 100)
				percent = 0;
			return percent*maxValue/100.0;
		}

		private double CoordToPercent(double coord, double maxValue)
		{
			if (coord > maxValue)
				coord = maxValue;
			return coord*100.0/maxValue;
		}

		private void BtnExpandAllClick(object sender, RoutedEventArgs e)
		{
			foreach (NetworkNode nwn in nodeCanvas.Children.OfType<NetworkNode>())
			{
				nwn.AlwaysShowLabel = !nwn.AlwaysShowLabel;
			}
		}

		public void CreateConnection(NetworkNode begin, NetworkNode end)
		{
			//we are always adding the end point of the connection pair, thus ignoring the home system in all cases. 
			//it is implied that the connection begins at the home system
			ConnectedNodes.Add(end.ComputerSystemId);
			Line l = CreateConnection(begin, end, zoomer.Zoom);
			LastConnectionPoint = end;
			connectionCanvas.Children.Add(l);
		}

		private Line CreateConnection(NetworkNode begin, NetworkNode end, double zoomFactor)
		{
			Line line = new Line();
			line.Stroke = new SolidColorBrush(Colors.White);
			line.StrokeThickness = 1.0/zoomFactor;
			line.StrokeDashArray = new DoubleCollection {3.0, 3.0};
			Point start = begin.GetPosition();
			Point stop = end.GetPosition();
			line.X1 = start.X;
			line.Y1 = start.Y;
			line.X2 = stop.X;
			line.Y2 = stop.Y;
			return line;
		}
	}
}

//namespace TheGameClient.TheGame.Webservices.Public.User
//{
//    using WorldMap;
//    public partial class SavedConnection
//    {
//        public static Line CreateConnection(NetworkNode begin, NetworkNode end, double zoomFactor)
//        {
//            Line line = new Line();
//            line.Stroke = new SolidColorBrush(Colors.White);
//            line.StrokeThickness = 1.0 / zoomFactor;
//            line.StrokeDashArray = new DoubleCollection() {3.0, 3.0};
//            Point start = begin.GetPosition();
//            Point stop = end.GetPosition();
//            line.X1 = start.X;
//            line.Y1 = start.Y;
//            line.X2 = stop.X;
//            line.Y2 = stop.Y;
//            return line;
//        }
//    }
//}